package stone926.mods.jukebox.mixin;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.JukeboxBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.JukeboxBlockEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.MusicDiscItem;
import net.minecraft.state.StateManager;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import stone926.mods.jukebox.blockstate.Properties;

@Mixin(JukeboxBlock.class)
public abstract class JukeboxMixin extends BlockWithEntity {

  @Shadow
  public abstract int getComparatorOutput(BlockState state, World world, BlockPos pos);

  protected JukeboxMixin(Settings settings) {
    super(settings);
  }

  @Inject(method = "<init>", at = @At("RETURN"))
  private void init(Settings settings, CallbackInfo ci) {
    setDefaultState(getDefaultState().with(Properties.DISC, 0));
  }

  @Inject(method = "appendProperties", at = @At("RETURN"))
  private void appendProperties(StateManager.Builder<Block, BlockState> builder, CallbackInfo ci) {
    builder.add(Properties.DISC);
  }

  @Inject(method = "onPlaced", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"))
  private void onPlaced(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack, CallbackInfo ci) {
    world.setBlockState(
      pos, world.getBlockState(pos).with(Properties.DISC, getComparatorOutput(state, world, pos)), 2
    );
  }

  @Inject(method = "onUse", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"))
  private void onUseRemoveRecord(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit, CallbackInfoReturnable<ActionResult> cir) {
    world.setBlockState(
      pos, world.getBlockState(pos).with(Properties.DISC, 0), 2
    );
  }

  @Inject(method = "setRecord", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/WorldAccess;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"))
  private void setRecord(WorldAccess world, BlockPos pos, BlockState state, ItemStack stack, CallbackInfo ci) {
    boolean b = world.setBlockState(
      pos, world.getBlockState(pos).with(Properties.DISC, __getComparatorOutput(world, pos)), 2
    );
  }

  private int __getComparatorOutput(WorldAccess world, BlockPos pos) {
    BlockEntity blockEntity = world.getBlockEntity(pos);
    if (blockEntity instanceof JukeboxBlockEntity) {
      Item item = ((JukeboxBlockEntity) blockEntity).getRecord().getItem();
      if (item instanceof MusicDiscItem) {
        return ((MusicDiscItem) item).getComparatorOutput();
      }
    }
    return 0;
  }

}
